package org.Yiran.timetale_re.block.decorate;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.Yiran.timetale_re.block.base.MultiBlockBase;
import org.Yiran.timetale_re.entity.SitEntity;
import org.jetbrains.annotations.NotNull;

import java.util.List;

/**
 * 椅子方块类 - 由两个部分组成的可坐多方块结构
 * 支持玩家坐下交互，由上下两个部分组成
 * <p>
 * 结构说明:
 * - LOWER_PART (0): 下半部分（座位），主方块，可交互
 * - UPPER_PART (1): 上半部分（靠背），辅助方块
 */
public class Chair extends MultiBlockBase {
    
    // ==================== 方块属性定义 ====================
    
    /** 方向属性，继承自 MultiBlockBase */
    public static final DirectionProperty FACING = MultiBlockBase.FACING;
    
    /** 部件ID属性，用于区分上下两个部分 */
    public static final IntegerProperty PART_ID = IntegerProperty.create("part_id", 0, 1);

    // ==================== 部件常量定义 ====================
    
    /** 下部分（座位） */
    public static final int LOWER_PART = 0;
    
    /** 上部分（靠背） */
    public static final int UPPER_PART = 1;

    // ==================== 构造函数和初始化 ====================

    /**
     * 构造函数
     * @param properties 方块属性
     * @param modId 模组ID
     * @param blockName 方块名称
     */
    public Chair(BlockBehaviour.Properties properties, String modId, String blockName) {
        super(properties, modId, blockName, 2,
                (name, part) -> "models/block/decorate/" + name + (part == LOWER_PART ? "_lower" : "_upper") + ".json");
        this.registerDefaultState(this.stateDefinition.any()
                .setValue(FACING, Direction.NORTH)
                .setValue(PART_ID, LOWER_PART));
    }

    @Override
    public IntegerProperty getPartIdProperty() {
        return PART_ID;
    }

    // ==================== 多方块结构管理 ====================

    /**
     * 放置其他部分（上半部分）
     * 当主部分被放置时，这个方法负责放置结构的其他部分
     * 
     * @param level 世界对象
     * @param basePos 基础位置（下半部分位置）
     * @param facing 朝向
     * @param mainPartId 主部分ID
     */
    @Override
    protected void placeOtherParts(Level level, BlockPos basePos, Direction facing, int mainPartId) {
        if (mainPartId == LOWER_PART) {
            // 放置上半部分在下半部分的正上方
            BlockPos upperPos = basePos.above();
            BlockState upperState = this.defaultBlockState()
                    .setValue(FACING, facing)
                    .setValue(PART_ID, UPPER_PART);
            level.setBlock(upperPos, upperState, 35);
        }
    }

    /**
     * 检查是否可以放置椅子
     * 验证在指定位置和朝向是否可以放置整个多方块结构
     * 
     * @param level 世界对象
     * @param pos 放置位置
     * @param facing 朝向
     * @return 是否可以放置
     */
    @Override
    protected boolean canPlaceAt(Level level, BlockPos pos, Direction facing) {
        // 只有当下半部分作为主方块放置时才进行检查
        BlockPos upperPos = pos.above();

        // 添加边界检查
        if (!level.isInWorldBounds(pos) || !level.isInWorldBounds(upperPos)) {
            return false;
        }

        // 检查是否有完整的方块支撑（下方）
        BlockPos posBelow = pos.below();
        BlockState belowState = level.getBlockState(posBelow);

        // 检查下方是否有完整方块支撑
        if (!isFullBlock(belowState)) {
            return false;
        }

        // 检查当前位置和上方位置是否可以替换
        BlockState currentPosState = level.getBlockState(pos);
        BlockState upperPosState = level.getBlockState(upperPos);

        return currentPosState.canBeReplaced() && upperPosState.canBeReplaced();
    }

    /**
     * 检查部件是否有效
     * 检查多方块结构的各个部分是否仍然有效连接
     * 
     * @param level 世界对象
     * @param pos 部件位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 部件是否有效
     */
    @Override
    protected boolean isPartValid(LevelReader level, BlockPos pos, Direction facing, int partId) {
        if (partId == LOWER_PART) {
            // 检查下方是否有完整方块支撑
            BlockPos posBelow = pos.below();
            BlockState belowState = level.getBlockState(posBelow);
            if (!isFullBlock(belowState)) {
                return false;
            }

            // 检查上半部分是否存在且位置正确
            BlockPos upperPos = pos.above();
            BlockState upperState = level.getBlockState(upperPos);
            return upperState.getBlock() == this &&
                    upperState.getValue(FACING) == facing &&
                    upperState.getValue(PART_ID) == UPPER_PART;
        } else { // UPPER_PART
            // 上半部分检查下方是否是椅子的下半部分
            BlockPos lowerPos = pos.below();
            BlockState lowerState = level.getBlockState(lowerPos);
            return lowerState.getBlock() == this &&
                    lowerState.getValue(FACING) == facing &&
                    lowerState.getValue(PART_ID) == LOWER_PART;
        }
    }

    /**
     * 检查方块是否能存活（下方有支撑）
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @return 是否能存活
     */
    @Override
    public boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) {
        int partId = state.getValue(PART_ID);
        if (partId == LOWER_PART) {
            // 下半部分检查下方是否有完整方块支撑
            BlockPos posBelow = pos.below();
            BlockState belowState = level.getBlockState(posBelow);
            return isFullBlock(belowState);
        } else {
            // 上半部分检查下方是否是椅子的下半部分
            BlockPos lowerPos = pos.below();
            BlockState lowerState = level.getBlockState(lowerPos);
            return lowerState.getBlock() == this &&
                    lowerState.getValue(PART_ID) == LOWER_PART &&
                    isFullBlock(level.getBlockState(lowerPos.below()));
        }
    }

    /**
     * 邻近方块变化时的处理
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param block 变化的方块
     * @param fromPos 变化的位置
     * @param isMoving 是否在移动
     */
    @Override
    @SuppressWarnings("deprecation")
    public void neighborChanged(BlockState state, @NotNull Level level, BlockPos pos, @NotNull Block block, @NotNull BlockPos fromPos, boolean isMoving) {
        int partId = state.getValue(PART_ID);

        BlockPos posBelow = pos.below();
        if (partId == LOWER_PART) {
            // 检查下方的方块是否被移除
            if (fromPos.equals(posBelow)) {
                BlockState belowState = level.getBlockState(posBelow);
                if (!isFullBlock(belowState)) {
                    // 如果下方方块不再是完整方块，则破坏整个椅子
                    this.destroyAndDrop(state, level, pos);
                    return;
                }
            }

            // 检查上方部分是否被移除
            BlockPos posAbove = pos.above();
            if (fromPos.equals(posAbove)) {
                BlockState aboveState = level.getBlockState(posAbove);
                if (aboveState.getBlock() != this || aboveState.getValue(PART_ID) != UPPER_PART) {
                    // 如果上方部分不存在，则破坏整个椅子
                    this.destroyAndDrop(state, level, pos);
                    return;
                }
            }
        } else {
            // 上半部分检查下方部分是否被移除
            if (fromPos.equals(posBelow)) {
                BlockState belowState = level.getBlockState(posBelow);
                if (belowState.getBlock() != this || belowState.getValue(PART_ID) != LOWER_PART) {
                    // 如果下方部分不存在，则破坏整个椅子
                    this.destroyAndDrop(state, level, pos);
                    return;
                }
            }
        }
        super.neighborChanged(state, level, pos, block, fromPos, isMoving);
    }

    /**
     * 移除其他部分
     * 当主部分被移除时，清理结构的其他部分
     * 
     * @param level 世界对象
     * @param pos 方块位置
     * @param facing 朝向
     * @param partId 部件ID
     */
    @Override
    protected void removeOtherParts(Level level, BlockPos pos, Direction facing, int partId) {
        if (partId == LOWER_PART) {
            // 移除上半部分
            BlockPos upperPos = pos.above();
            BlockState upperState = level.getBlockState(upperPos);
            if (upperState.getBlock() == this && upperState.getValue(PART_ID) == UPPER_PART) {
                level.destroyBlock(upperPos, true);
            }
        } else {
            // 移除下半部分
            BlockPos lowerPos = pos.below();
            BlockState lowerState = level.getBlockState(lowerPos);
            if (lowerState.getBlock() == this && lowerState.getValue(PART_ID) == LOWER_PART) {
                level.destroyBlock(lowerPos, true);
            }
        }
    }

    /**
     * 获取部件位置
     * @param basePos 基础位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 部件位置
     */
    @Override
    protected BlockPos getPartPosition(BlockPos basePos, Direction facing, int partId) {
        return switch (partId) {
            case LOWER_PART -> basePos;
            case UPPER_PART -> basePos.above();
            default -> null;
        };
    }

    /**
     * 获取预期邻居位置
     * @param pos 方块位置
     * @param facing 朝向
     * @param partId 部件ID
     * @return 预期邻居位置
     */
    @Override
    protected BlockPos getExpectedNeighborPos(BlockPos pos, Direction facing, int partId) {
        return switch (partId) {
            case LOWER_PART -> pos.above();      // 下半部分邻居在上方
            case UPPER_PART -> pos.below();      // 上半部分邻居在下方
            default -> null;
        };
    }

    /**
     * 预放置视觉效果（客户端）
     * @param level 世界对象
     * @param basePos 基础位置
     * @param facing 朝向
     */
    @Override
    protected void prePlaceVisual(Level level, BlockPos basePos, Direction facing) {
        if (level.isClientSide) {
            // 预放置上半部分（part_id=1）
            BlockPos partPos = getPartPosition(basePos, facing, UPPER_PART);
            if (partPos != null) {
                BlockState partState = this.defaultBlockState()
                        .setValue(FACING, facing)
                        .setValue(PART_ID, UPPER_PART);
                // 使用 Block.UPDATE_IMMEDIATE | Block.UPDATE_KNOWN_SHAPE 确保立即显示
                level.setBlock(partPos, partState, 10);
            }
        }
    }

    // ==================== 物品掉落处理 ====================

    /**
     * 移除方块时掉落物品
     * 当多方块结构被移除时，处理物品掉落逻辑
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     */
    @Override
    protected void dropItemsOnRemove(BlockState state, Level level, BlockPos pos) {
    }

    /**
     * 破坏方块并确保掉落物品
     */
    private void destroyAndDrop(BlockState state, Level level, BlockPos pos) {
        // 移除整个多方块结构
        Direction facing = state.getValue(FACING);
        int partId = state.getValue(PART_ID);
        removeAllParts(level, pos, facing, partId);

        // 查找并移除绑定到这个椅子的坐姿实体
        if (!level.isClientSide) {
            BlockPos chairPos = partId == LOWER_PART ? pos : pos.below();
            levelBlockPos(level, chairPos);
        }

        // 只有主部分（下半部分）负责掉落物品
        if (partId == LOWER_PART) {
            // 掉落物品
            popResource(level, pos, new ItemStack(this));
        }
    }

    /**
     * 移除整个多方块结构，确保破坏粒子效果和物品掉落
     */
    private void removeAllParts(Level level, BlockPos pos, Direction facing, int partId) {
        if (!level.isClientSide) {
            // 先移除其他部分
            removeOtherParts(level, pos, facing, partId);
            // 然后移除自身部分
            level.removeBlock(pos, false);
        }
    }

    // ==================== 坐下交互处理 ====================

    /**
     * 方块使用处理（坐下交互）
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @return 交互结果
     */
    @Override
    @SuppressWarnings("deprecation")
    public @NotNull InteractionResult use(BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hit) {
        // 只有下半部分椅子才能让玩家坐下
        if (state.getValue(PART_ID) == LOWER_PART) {
            // 检查玩家是否已经在坐姿状态
            if (player.isPassenger()) {
                return InteractionResult.PASS;
            }

            // 设置玩家视角朝向椅子前方
            Direction facing = state.getValue(FACING);
            this.setPlayerFacingDirection(player, facing);

            // 在服务端创建坐姿实体并让玩家骑乘
            if (!level.isClientSide) {
                // 创建坐姿实体，位置稍微高于椅子底部
                SitEntity sitEntity = new SitEntity(level,
                        new Vec3(pos.getX() + 0.5, pos.getY() + 0.45, pos.getZ() + 0.5),
                        facing.get2DDataValue(), pos);

                // 将实体添加到世界
                level.addFreshEntity(sitEntity);

                // 让玩家骑乘坐姿实体
                player.startRiding(sitEntity);
            }

            return InteractionResult.SUCCESS;
        }

        return InteractionResult.PASS;
    }

    /**
     * 设置玩家面朝椅子前方
     * @param player 玩家
     * @param facing 椅子朝向
     */
    private void setPlayerFacingDirection(Player player, Direction facing) {
        float yaw = switch (facing) {
            case NORTH -> 180.0f;  // 椅子朝北，玩家面朝北
            case SOUTH -> 0.0f;    // 椅子朝南，玩家面朝南
            case WEST -> 90.0f;    // 椅子朝西，玩家面朝西
            case EAST -> -90.0f;   // 椅子朝东，玩家面朝东
            default -> 0.0f;
        };
        player.setYRot(yaw);
    }

    // ==================== 玩家破坏处理 ====================

    /**
     * 玩家将要破坏方块时的处理
     * @param level 世界对象
     * @param pos 方块位置
     * @param state 方块状态
     * @param player 玩家
     */
    @Override
    public void playerWillDestroy(Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Player player) {
        // 当玩家破坏椅子时确保让玩家站起来
        if (!level.isClientSide) {
            BlockPos chairPos = state.getValue(PART_ID) == LOWER_PART ? pos : pos.below();
            levelBlockPos(level, chairPos);
        }
        super.playerWillDestroy(level, pos, state, player);
    }

    // ==================== 辅助方法 ====================

    /**
     * 检查方块是否为完整方块（具有完整的碰撞箱）
     */
    private boolean isFullBlock(BlockState state) {
        if (state == null || state.getBlock() == Blocks.AIR) {
            return false;
        }
        // 检查是否为完整方块形状
        return Shapes.joinIsNotEmpty(state.getCollisionShape(null, null), Shapes.block(), BooleanOp.AND);
    }

    /**
     * 解除椅子上的坐姿实体
     * @param level 世界对象
     * @param chairPos 椅子位置
     */
    private void levelBlockPos(Level level, BlockPos chairPos) {
        List<SitEntity> entities = level.getEntitiesOfClass(SitEntity.class, new AABB(chairPos).inflate(1.0));
        for (SitEntity entity : entities) {
            if (entity.getChairPosition().equals(chairPos)) {
                // 让所有乘客下来
                for (Entity passenger : entity.getPassengers()) {
                    if (passenger instanceof Player) {
                        passenger.stopRiding();
                    }
                }
                entity.discard();
            }
        }
    }
}